/********************************************************************************************************
 * @file    sampleSensor.c
 *
 * @brief   This is the source file for sampleSensor
 *
 * @author  Zigbee Group
 * @date    2021
 *
 * @par     Copyright (c) 2021, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 *			All rights reserved.
 *
 *          Licensed under the Apache License, Version 2.0 (the "License");
 *          you may not use this file except in compliance with the License.
 *          You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 *          Unless required by applicable law or agreed to in writing, software
 *          distributed under the License is distributed on an "AS IS" BASIS,
 *          WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *          See the License for the specific language governing permissions and
 *          limitations under the License.
 *
 *******************************************************************************************************/

#if (__PROJECT_TL_CONTACT_SENSOR__)

/**********************************************************************
 * INCLUDES
 */
#include "tl_common.h"
#include "zb_api.h"
#include "zcl_include.h"
#include "bdb.h"
#include "ota.h"
#include "sampleSensor.h"
#include "app_ui.h"
#include "../sensor/GXHT30.h"
#include "../xiaomi/zcl_mi.h"

/**********************************************************************
 * LOCAL CONSTANTS
 */
#if PM_ENABLE
/**
 *  @brief Definition for wakeup source and level for PM
 */
drv_pm_pinCfg_t g_sensorPmCfg[] = { { BUTTON1, PM_WAKEUP_LEVEL } };
#endif

static s16 tempSendOld;
static u16 humiditySendOld;
/**********************************************************************
 * TYPEDEFS
 */

/**********************************************************************
 * GLOBAL VARIABLES
 */

app_ctx_t g_sensorAppCtx;

u8 nwkRetryTime = 0;

//Must declare the application call back function which used by ZDO layer
const zdo_appIndCb_t appCbLst = { bdb_zdoStartDevCnf,//start device cnf cb
		NULL,//reset cnf cb
		NULL,//device announce indication cb
		sampleSensor_leaveIndHandler,//leave ind cb
		sampleSensor_leaveCnfHandler,//leave cnf cb
		NULL,//nwk update ind cb
		NULL,//permit join ind cb
		NULL,//nlme sync cnf cb
		NULL,//tc join ind cb
		NULL, //tc detects that the frame counter is near limit
		};

/**
 *  @brief Definition for bdb commissioning setting
 */
bdb_commissionSetting_t g_bdbCommissionSetting = { .linkKey.tcLinkKey.keyType =
		SS_GLOBAL_LINK_KEY,
		.linkKey.tcLinkKey.key = (u8 *) tcLinkKeyCentralDefault, //can use unique link key stored in NV

		.linkKey.distributeLinkKey.keyType = MASTER_KEY,
		.linkKey.distributeLinkKey.key = (u8 *) linkKeyDistributedMaster, //use linkKeyDistributedCertification before testing

		.linkKey.touchLinkKey.keyType = MASTER_KEY, .linkKey.touchLinkKey.key =
				(u8 *) touchLinkKeyMaster, //use touchLinkKeyCertification before testing

#if TOUCHLINK_SUPPORT
		.touchlinkEnable = 1, /* enable touch-link */
#else
		.touchlinkEnable = 0, /* disable touch-link */
#endif
		.touchlinkChannel = DEFAULT_CHANNEL, /* touch-link default operation channel for target */
		.touchlinkLqiThreshold = 0xA0, /* threshold for touch-link scan req/resp command */
};

/**********************************************************************
 * LOCAL VARIABLES
 */

/**********************************************************************
 * FUNCTIONS
 */
void GXHT30_meas(void);
void battery_meas(void);
/*********************************************************************
 * @fn      stack_init
 *
 * @brief   This function initialize the ZigBee stack and related profile. If HA/ZLL profile is
 *          enabled in this application, related cluster should be registered here.
 *
 * @param   None
 *
 * @return  None
 */
void stack_init(void) {
	zb_init();
	zb_zdoCbRegister((zdo_appIndCb_t *) &appCbLst);
}

/*********************************************************************
 * @fn      user_app_init
 *
 * @brief   This function initialize the application(Endpoint) information for this node.
 *
 * @param   None
 *
 * @return  None
 */
void user_app_init(void) {
#if ZCL_POLL_CTRL_SUPPORT
	af_powerDescPowerModeUpdate(POWER_MODE_RECEIVER_COMES_PERIODICALLY);
#else
	af_powerDescPowerModeUpdate(POWER_MODE_RECEIVER_COMES_WHEN_STIMULATED);
#endif
	zcl_reportingTabInit();
	/* Initialize ZCL layer */
	/* Register Incoming ZCL Foundation command/response messages */
	zcl_init(sampleSensor_zclProcessIncomingMsg);

	/* Register endPoint */
	af_endpointRegister(SAMPLE_SENSOR_ENDPOINT,
			(af_simple_descriptor_t *) &sampleSensor_simpleDesc,
			zcl_rx_handler, NULL);

	/* Register ZCL specific cluster information */
	zcl_register(SAMPLE_SENSOR_ENDPOINT, SAMPLE_SENSOR_CB_CLUSTER_NUM,
			(zcl_specClusterInfo_t *) g_sampleSensorClusterList);

}

void led_init(void) {
	light_init();
}

void report_handler(void) {
	if (zb_isDeviceJoinedNwk()) {
		if (zcl_reportingEntryActiveNumGet()) {
			reportNoMinLimit();

			//start report timer
			reportAttrTimerStart(REGULAR_REPORT_INTERVAL);
		} else {
			//stop report timer
			reportAttrTimerStop();
		}
	}
}

void app_task(void) {
	app_key_handler();

	if (bdb_isIdle()) {
#if PM_ENABLE
		drv_pm_lowPowerEnter();
		/*
		 if (!g_sensorAppCtx.keyPressed) {
		 drv_pm_lowPowerEnter();
		 }
		 */
#endif

		//report_handler();
	}
}

static void sampleSensorSysException(void) {
#if 1
	//SYSTEM_RESET();
	drv_pm_sleep(PM_SLEEP_MODE_DEEPSLEEP, 0, 0);
#else
	light_on();
	while(1);
#endif
}

void GXHT30_meas(void) {
	printf("nwk:%d ", zb_isDeviceJoinedNwk());
	u8 tempData[6];
	if (GXHT30_onceMeas(tempData)) {
		//printf("temp data: %x %x %x %x %x %x",tempData[0],tempData[1],tempData[2],tempData[3],tempData[4],tempData[5]);
		u16 tempRaw, humidityRaw;
		float temp, humidity;
		tempRaw = tempData[0] << 8 | tempData[1];
		humidityRaw = tempData[3] << 8 | tempData[4];
		temp = 175 * ((float) tempRaw / 65535) - 45;
		humidity = 100 * ((float) humidityRaw / 65535);
		s16 zclTemp;
		u16 zclHumidity;
		zclTemp = 100 * temp;
		zclHumidity = 100 * humidity;
		printf("temp: %d \t humi: %d \n", zclTemp, zclHumidity);
		zcl_setAttrVal(SAMPLE_SENSOR_ENDPOINT,
				ZCL_CLUSTER_MS_TEMPERATURE_MEASUREMENT,
				ZCL_TEMPERATURE_MEASUREMENT_ATTRID_MEASUREDVALUE,
				(u8*) &zclTemp);
		zcl_setAttrVal(SAMPLE_SENSOR_ENDPOINT,
				ZCL_CLUSTER_MS_RELATIVE_HUMIDITY,
				ZCL_HUMIDITY_MEASUREMENT_ATTRID_MEASUREDVALUE,
				(u8*) &zclHumidity);
	} else {
		if (nwkRetryTime == NWK_RETRY_TIMES) {
			printf("gxht30 com error\n");
			drv_pm_sleep(PM_SLEEP_MODE_DEEPSLEEP, PM_WAKEUP_SRC_PAD, 0);
		} else {
			nwkRetryTime++;
		}
		nwkRetryTime++;
	}
}

void battery_meas(void) {
	u16 batteryVoltage = drv_get_adc_data();
	u8 zclBatteryVoltage = batteryVoltage / 100;
	u8 zclBatteryRemaining = 0;
	if (batteryVoltage > 3200) {
		zclBatteryRemaining = 200;
	} else {
		zclBatteryRemaining = 2 * (batteryVoltage - BATTERY_SAFETY_THRESHOLD)
				/ ((3200 - BATTERY_SAFETY_THRESHOLD) / 100);
	}
	printf("battery voltage: %d percentage: %d\n", batteryVoltage,
			zclBatteryRemaining);
	zcl_setAttrVal(SAMPLE_SENSOR_ENDPOINT, ZCL_CLUSTER_GEN_POWER_CFG,
			batteryVoltage, (u8*) &zclBatteryVoltage);
	zcl_setAttrVal(SAMPLE_SENSOR_ENDPOINT, ZCL_CLUSTER_GEN_POWER_CFG,
			ZCL_ATTRID_BATTERY_PERCENTAGE_REMAINING, (u8*) &zclBatteryRemaining);

	mi_batteryReport(batteryVoltage,*zcl_temperatureAttrGet().temperatureValue,*zcl_humidityAttrGet().humidityValue);
}

s32 GXHT30_periodicMeas(void *arg) {
	if (zb_isDeviceJoinedNwk()) {
		GXHT30_meas();

		if (((*zcl_temperatureAttrGet().temperatureValue - tempSendOld)> TEMP_REPORT_INTERVAL) | ((tempSendOld - *zcl_temperatureAttrGet().temperatureValue)> TEMP_REPORT_INTERVAL)) {
			tempSendOld = *zcl_temperatureAttrGet().temperatureValue;
			mi_tempReport();
		}

		if (((*zcl_humidityAttrGet().humidityValue - humiditySendOld)> HUMIDITY_REPORT_INTERVAL) | ((humiditySendOld - *zcl_humidityAttrGet().humidityValue) > HUMIDITY_REPORT_INTERVAL)) {
			humiditySendOld = *zcl_humidityAttrGet().humidityValue;
			mi_humidityReport();
		}

		return 0;
	} else {
		printf("leave nwk,stop measure gxht30\n");
		return -1;
	}

}

s32 battery_periodicMeas(void *arg) {

	if (zb_isDeviceJoinedNwk()) {
		battery_meas();

		return 0;
	} else {
		printf("leave nwk,stop measure voltage\n");
		return -1;
	}
	return 0;
}
/*********************************************************************
 * @fn      user_init
 *
 * @brief   User level initialization code.
 *
 * @param   isRetention - if it is waking up with ram retention.
 *
 * @return  None
 */
void user_init(bool isRetention) {
	/* Initialize LEDs*/
	led_init();

#if PM_ENABLE
	drv_pm_wakeupPinConfig(g_sensorPmCfg,
			sizeof(g_sensorPmCfg) / sizeof(drv_pm_pinCfg_t));
#endif

	if (!isRetention) {
		/* Initialize Stack */
		stack_init();

		/* Initialize user application */
		user_app_init();

		/* Register except handler for test */
		sys_exceptHandlerRegister(sampleSensorSysException);

		/* User's Task */

		ev_on_poll(EV_POLL_IDLE, app_task);

		/* Load the pre-install code from flash */
		if (bdb_preInstallCodeLoad(&g_sensorAppCtx.tcLinkKey.keyType,
				g_sensorAppCtx.tcLinkKey.key) == RET_OK) {
			g_bdbCommissionSetting.linkKey.tcLinkKey.keyType
					= g_sensorAppCtx.tcLinkKey.keyType;
			g_bdbCommissionSetting.linkKey.tcLinkKey.key
					= g_sensorAppCtx.tcLinkKey.key;
		}

		u8 reportableChange = 0x00;
		bdb_defaultReportingCfg(SAMPLE_SENSOR_ENDPOINT, HA_PROFILE_ID,
				ZCL_CLUSTER_GEN_POWER_CFG,
				ZCL_ATTRID_BATTERY_PERCENTAGE_REMAINING, 0x0000, 0x003c,
				(u8 *) &reportableChange);
		bdb_defaultReportingCfg(SAMPLE_SENSOR_ENDPOINT, HA_PROFILE_ID,
				ZCL_CLUSTER_MS_TEMPERATURE_MEASUREMENT,
				ZCL_TEMPERATURE_MEASUREMENT_ATTRID_MEASUREDVALUE, 0x0000,
				0x003c, (u8 *) &reportableChange);
		bdb_defaultReportingCfg(SAMPLE_SENSOR_ENDPOINT, HA_PROFILE_ID,
				ZCL_CLUSTER_MS_RELATIVE_HUMIDITY,
				ZCL_HUMIDITY_MEASUREMENT_ATTRID_MEASUREDVALUE, 0x0000, 0x003c,
				(u8 *) &reportableChange);
		/* Initialize BDB */printf("init done\n");
		GXHT30_meas();
		battery_meas();

		u8 repower = drv_pm_deepSleep_flag_get() ? 0 : 1;
		bdb_init((af_simple_descriptor_t *) &sampleSensor_simpleDesc,
				&g_bdbCommissionSetting, &g_zbDemoBdbCb, repower);
	} else {
		/* Re-config phy when system recovery from deep sleep with retention */mac_phyReconfig();
	}
}

#endif  /* __PROJECT_TL_CONTACT_SENSOR__ */
